package org.egrit.image;

import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.RenderedImage;

import org.egrit.AbstractGrid;
import org.egrit.GridBoundsFactory;
import org.egrit.IGridBounds;
import org.egrit.util.Args;

import org.jaitools.imageutils.iterator.SimpleIterator;

/**
 * A grid backed by a {@linkplain RenderedImage}.
 *
 * @author michael
 */
public class ImageBackedGrid extends AbstractGrid {

    protected final RenderedImage backingImage;
    protected final SimpleIterator readIter;
    
    private static IGridBounds makeBounds(RenderedImage backimgImage) {
        Args.notNull("backimgImage", backimgImage);
        
        Rectangle rect = new Rectangle(
                backimgImage.getMinX(), backimgImage.getMinY(), 
                backimgImage.getWidth(), backimgImage.getHeight());

        return GridBoundsFactory.create(rect);
    }
    
    /**
     * Creates a new grid from the given raster image. The grid bounds are taken
     * directly from the minimum and maximum pixel ordinates of the image.
     * 
     * @param backingImage the backing image
     * 
     * @param outsideValue value to return for queries beyond the grid boundaries
     *     (may be {@code null})
     * 
     * @throws IllegalArgumentException if {@code backingImage} is {@code null}
     */
    ImageBackedGrid(RenderedImage backingImage, Number outsideValue) {
        super(makeBounds(backingImage), outsideValue);

        this.backingImage = backingImage;
        this.readIter = new SimpleIterator(backingImage, null, outsideValue);
    }
    
    @Override
    public Number getGridValue(int gridX, int gridY) {
        // Note: the iterator will return null if the position is beyond
        // its bounds (which equal the grid bounds)
        Number value = readIter.getSample(gridX, gridY);
        return value == null ? outsideValue : value;
    }

    @Override
    public Number getGridValue(Point gridPos) {
        if (gridPos == null) {
            throw new IllegalArgumentException("argument must not be null");
        }
        return getGridValue(gridPos.x, gridPos.y);
    }

}
